<?php

declare(strict_types=1);

namespace app\admin\controller\auth;

use app\Request;
use think\facade\Db;
use sheep\controller\Backend;
use sheep\exception\SheepException;
use app\admin\model\auth\Access as AccessModel;
use sheep\library\Tree;


class Access extends Backend
{

    protected function initialize()
    {
        $this->model = new AccessModel();
    }

    /**
     * 权限列表
     */
    public function list()
    {
        $parent_id = $this->request->param('parent_id', 0);

        $data = (new Tree(function () {
            return $this->model->order('weigh desc, id asc');
        }))->getTree($parent_id);

        return success('', $data);
    }


    /**
     * 添加权限
     */
    public function add(Request $request)
    {
        if (!$this->auth()->isSuper()) {
            throw new SheepException('仅超级管理员可操作');
        }

        $params = $request->only(['parent_id', 'name', 'title', 'type', 'icon', 'params', 'weigh', 'status', 'api']);
        $this->svalidate($params, ".add");

        $data = Db::transaction(function () use ($params) {
            $access = $this->model->save($params);
            if ($params['type'] === 'page' && !empty($params['api'])) {
                $apiAccess = [];
                foreach ($params['api'] as $api) {
                    $apiAccess[] = $this->getApiAccess($api, $this->model);
                }
                (new AccessModel)->saveAll($apiAccess);
            }
            return $access;
        });

        return success('保存成功', $data);
    }

    /**
     * 权限节点详情
     */
    public function detail($id)
    {
        if (!$this->auth()->isSuper()) {
            throw new SheepException('仅超级管理员可操作');
        }

        $data = $this->model->findOrFail($id);
        return success('获取成功', $data);
    }


    /**
     * 更新
     */
    public function edit(Request $request, $id)
    {
        if (!$this->auth()->isSuper()) {
            throw new SheepException('仅超级管理员可操作');
        }

        $params = $request->only(['parent_id', 'name', 'title', 'type', 'icon', 'params', 'weigh', 'status', 'api']);
        $params['id'] = $id;
        $this->svalidate($params);

        $data = $this->model->findOrFail($id);

        Db::transaction(function () use ($data, $params) {
            $data->save($params);
        });

        return success('更新成功', $data);
    }


    /**
     * 删除权限节点
     */
    public function delete($id)
    {
        if (!$this->auth()->isSuper()) {
            throw new SheepException('仅超级管理员可操作');
        }

        $access = $this->model->findOrFail($id);

        $child = $this->model->where('parent_id', $access->id)->count();
        if ($child) {
            throw new SheepException("请先删除下级节点");
        }

        Db::transaction(function () use ($access) {
            $access->delete();
            // TODO 需删除角色组权限策略并更新角色组权限缓存
        });

        return success('删除成功');
    }

    // 组装Api权限
    private function getApiAccess(array $api, $parentAccess)
    {
        $apiAccess = [
            'title' => $api['title'],
            'name' => "{$parentAccess->name}.{$api['name']}",
            'type' => 'api',
            'parent_id' => $parentAccess->id
        ];
        // 检查权限标识是否重复
        $this->svalidate($apiAccess);
        return $apiAccess;
    }

    /**
     * 选择权限节点
     */
    public function select(Request $request)
    {
        $params = $request->only(['role_id', 'parent_id']);

        $role_id = $this->auth()->user()->role_id;

        if (!empty($params['role_id'])) {
            $role_id = intval($params['role_id']);
            if (!$this->auth()->isSuper() && !in_array($role_id, $this->auth()->getChildRoleIds(true))) {
                throw new SheepException("无权限查看该角色组权限列表");
            }
        }
        $rules = $this->auth()->getRulesByRole($role_id);

        $data = (new Tree(function () use ($rules) {
            return $this->model->whereIn('id', $rules)->field("id, name, title, type, icon")->order('weigh desc');
        }))->getTree($params['parent_id']);


        return success('选择权限', $data);
    }
}
